import {createElement} from './element'

// 拖动点颜色
const DRAG_POINT_COLOR = '#00AFFF';
// 拖动点的宽高尺寸
const POINT_SIZE = 11;
// 最小图片尺寸
const MIN_IMAGE_WIDTH = 200;
const MIN_IMAGE_HEIGHT = 100;
// 边框尺寸
const BORDER_WIDTH = 2;

/**
 * 改变元素尺寸类
 */
class Cat2DocResize {
    #parentElement = null;
    #currentElement = null;
    #points = null;
    #isDragging = false;
    #prevDragPos = null;
    #elementMouseEnter = this.#handleElementMouseEnter.bind(this);
    #elementMouseLeave = this.#handleElementMouseLeave.bind(this);
    #pointMouseEnter = this.#handlePointMouseEnter.bind(this);
    #pointMouseLeave = this.#handlePointMouseLeave.bind(this);
    #pointMouseDown = this.#handlePointMouseDown.bind(this);
    #pointDrag = this.#handleDrag.bind(this);
    #pointStopDrag = this.#handleStopDrag.bind(this);
    constructor(parentElement) {
        this.#parentElement = parentElement;
        // 设置拖动点
        this.#points = [createDragPoint(parentElement), createDragPoint(parentElement), createDragPoint(parentElement), createDragPoint(parentElement)];
        this.#points.forEach((p, index)=>{
            p.addEventListener('mouseenter', this.#pointMouseEnter);
            p.addEventListener('mouseleave', this.#pointMouseLeave);
            p.addEventListener('mousedown', this.#pointMouseDown);
            // 设置拖动点的光标样式
            switch (index) {
                case 0:
                case 2:
                    p.style.cursor = 'nwse-resize';
                    break;
                case 1:
                case 3:
                    p.style.cursor = 'nesw-resize';
                    break;
            }
        });
        document.addEventListener('mousemove', this.#pointDrag);
        document.addEventListener('mouseup', this.#pointStopDrag);
    }
    get #maxWidth() {
        const rect = this.#parentElement.getBoundingClientRect();
        return rect.width * 0.95;
    }
    /** 添加元素拖动功能 */
    addDrag(element) {
        element.style.borderWidth = BORDER_WIDTH+'px';
        element.style.borderStyle= 'solid';
        element.style.borderColor= '#0000';
        element.addEventListener('mouseenter', this.#elementMouseEnter);
        element.addEventListener('mouseleave', this.#elementMouseLeave);
    }
    /** 移除元素拖动功能 */
    removeDrag(element) {
        element.style.borderWidth = '0px';
        element.style.borderStyle= '';
        element.removeEventListener('mouseenter', this.#elementMouseEnter);
        element.removeEventListener('mouseleave', this.#elementMouseLeave);
    }
    isType(element) {
        if(!element) return false;
        return Array.from(this.#points).includes(element);
    }
    destory() {
        this.#points.forEach(p=>{
            p.removeEventListener('mouseenter', this.#pointMouseEnter);
            p.removeEventListener('mouseleave', this.#pointMouseLeave);
            p.removeEventListener('mousedown', this.#pointMouseDown);
            p.remove();
        });
        document.removeEventListener('mousemove', this.#pointDrag);
        document.removeEventListener('mouseup', this.#pointStopDrag);
        this.#points = [];
    }
    /** 元素鼠标进入事件 */
    #handleElementMouseEnter(event) {
        if(this.#isDragging) {
            return;
        }
        if(event) {this.#currentElement = event.target}
        this.#resetPoints();
    }
    /** 元素鼠标离开事件 */
    #handleElementMouseLeave(event) {
        if(this.#isDragging) {
            return;
        }
        this.#points.forEach(p=>{
            p.style.display = 'none'
        });
        event.target.style.borderColor = '#0000'
    }

    /** 拖动点鼠标进入事件 */
    #handlePointMouseEnter() {
        this.#points.forEach(p=>{
            p.style.display = 'block'
        });
        if(this.#currentElement) {
            this.#currentElement.style.borderColor = DRAG_POINT_COLOR;
        }
    }
    /** 拖动点鼠标离开事件 */
    #handlePointMouseLeave() {
        this.#points.forEach(p=>{
            p.style.display = 'none'
        });
        if(this.#currentElement) {
            this.#currentElement.style.borderColor = '#0000'
        }
    }

    /** 拖动点鼠标点下事件 */
    #handlePointMouseDown(event) {
        this.#isDragging = true;
        this.#points.forEach((b,index)=>{
            if(event.target === b) {
                this.#prevDragPos = {
                    index: index,
                    x: event.clientX,
                    y: event.clientY
                }
            }
        });
        // 禁止拖动时选中文本
        document.onselectstart = function() { return false; };
        document.ondragstart = function() { return false; };
    }
    /** 处理拖动事件 */
    #handleDrag(event) {
        if (this.#isDragging && this.#prevDragPos) {
            let width = event.clientX - this.#prevDragPos.x;
            let height = event.clientY - this.#prevDragPos.y;
            // TODO 如果是图片类型，边框宽度影响宽度计算；如果是Table，宽度不影响，这个问题原理为止，待后期学习了解。
            const borderWidth = this.#currentElement.tagName==='IMG'?BORDER_WIDTH:0;
            switch (this.#prevDragPos.index) {
                case 0:
                    width *= -1;
                    height *= -1;
                    break;
                case 1:
                    height *= -1;
                    break;
                case 2:
                    break;
                case 3:
                    width *= -1;
                    break;
            }
            const rect = this.#currentElement.getBoundingClientRect();
            width = Math.max(rect.width + width - borderWidth * 2, MIN_IMAGE_WIDTH);
            height = Math.max(rect.height + height - borderWidth * 2, MIN_IMAGE_HEIGHT);
            width = Math.min(this.#maxWidth, width);
            this.#currentElement.setAttribute('width', width);
            this.#currentElement.setAttribute('height', height);
            this.#prevDragPos = {
                index: this.#prevDragPos.index,
                x: event.clientX,
                y: event.clientY
            }
            this.#resetPoints();
        }
    }
    /** 处理停止拖动事件 */
    #handleStopDrag() {
        this.#handlePointMouseLeave();
        this.#isDragging = false;
        this.#prevDragPos = null;

        // 去除禁止拖动时选中文本
        document.onselectstart = null;
        document.ondragstart = null;
    }
    /** 重设拖动点 */
    #resetPoints() {
        this.#points.forEach((b,index)=>{
            switch (index) {
                case 0:
                    b.style.left = this.#currentElement.offsetLeft-POINT_SIZE/2+'px';
                    b.style.top = this.#currentElement.offsetTop-POINT_SIZE/2+'px';
                    break;
                case 1:
                    b.style.left = this.#currentElement.offsetLeft+this.#currentElement.offsetWidth-POINT_SIZE/2-BORDER_WIDTH+'px';
                    b.style.top = this.#currentElement.offsetTop-POINT_SIZE/2+'px';
                    break;
                case 2:
                    b.style.left = this.#currentElement.offsetLeft+this.#currentElement.offsetWidth-POINT_SIZE/2-BORDER_WIDTH+'px'
                    b.style.top = this.#currentElement.offsetTop+this.#currentElement.offsetHeight-POINT_SIZE/2-BORDER_WIDTH+'px';
                    break;
                case 3:
                    b.style.left = this.#currentElement.offsetLeft-POINT_SIZE/2+'px';
                    b.style.top = this.#currentElement.offsetTop+this.#currentElement.offsetHeight-POINT_SIZE/2-BORDER_WIDTH+'px';
                    break;
            }
            b.style.display = 'block'
        });

        this.#currentElement.style.borderColor = DRAG_POINT_COLOR;
    }
}
/** 创建拖动点 */
function createDragPoint(parentElement) {
    return createElement('div', parentElement, {
        className: 'resize-point',
        style: {
            width: POINT_SIZE+'px',
            height: POINT_SIZE+'px',
            position: 'absolute',
            display: 'none',
            zIndex: '999',
            borderStyle: 'solid',
            borderColor: DRAG_POINT_COLOR,
            borderWidth: BORDER_WIDTH+'px',
        }
    })
}

export default Cat2DocResize;

